/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bibp2pdesk;

import XMLCatalog.CatalogClass;
import XMLCatalog.FileClass;
import XMLCatalog.ObjectFactory;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 *
 * @author daniel
 */
public class CatalogServer extends Thread {

    private ServerSocket serverSocket;
    private Socket socket = null;
    private OutputStream out = null;
    private DataOutputStream dos = null;
    private InputStream in = null;
    private DataInputStream dis = null;
    private static final String CATALOG_PATH = "/tmp/catalog.xml";
    private ObjectFactory factory;
    private CatalogClass catalog;
    private String port;

    public CatalogServer(String port) {

        this.port = port;

        factory = new ObjectFactory();
   
        catalog = loadCatalog(CATALOG_PATH);

        if (catalog == null) {
            catalog = factory.createCatalogClass();
        }

    }

    public void run() {

        try {

            serverSocket = new ServerSocket(Integer.decode(port.split(":")[1]));

            while (true) {

                socket = serverSocket.accept();
                out = socket.getOutputStream();
                dos = new DataOutputStream(out);
                in = socket.getInputStream();
                dis = new DataInputStream(in);

                int type = recvType();
                byte data[] = recvData();
//                System.out.println("bla " + type);

                if (type == 1) { //Insert File

                    FileClass file = unmarshalFile(data);
                    if ( insertFile(file) == true) {
                        String success = "Success";
                        sendData(4,success.getBytes()); //sucesso
                    } else {
                        String error = "Error";
                        sendData(5,error.getBytes()); //erro
                    }

                } else if (type == 2) { //Search File

                    FileClass file = unmarshalFile(data);
                    List<FileClass> result = searchFile(file);

                    CatalogClass aux = factory.createCatalogClass();
                    FileClass current;
                    Iterator<FileClass> iterator = result.iterator();

                    while (iterator.hasNext()) {

                        current = iterator.next();
                        aux.getFile().add(current);

                    }

                    if ( aux.getFile().isEmpty() == false ) {
                        sendData(4,marshalCatalog(aux)); //sucesso
                    } else {
                        String error = "Error";
                        sendData(5,error.getBytes()); //erro
                    }

                } else if (type == 3) { //Remove File



                }

            }

        } catch (IOException ex) {
            Logger.getLogger(CatalogServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public FileClass searchFile(String key) {

        FileClass current;
        Iterator<FileClass> iterator = catalog.getFile().iterator();

        while (iterator.hasNext()) {

            current = iterator.next();

            if (current.getKey().compareTo(key) == 0) {

                return current;

            }

        }

        return null;

    }

    public List<FileClass> searchFile(FileClass model) {

        if (catalog.getFile() == null) return null;

        FileClass current;
        List<FileClass> result = new ArrayList<FileClass>();
        Iterator<FileClass> iterator = catalog.getFile().iterator();

        while (iterator.hasNext()) {

            current = iterator.next();

            if (!model.getTitle().isEmpty()
                    && (current.getTitle().compareTo(model.getTitle())) != 0) {

                continue;

            } else if (!model.getSubject().isEmpty()
                    && (current.getSubject().compareTo(model.getSubject())) != 0) {

                continue;

            } else if (!model.getDescription().isEmpty()
                    && (current.getDescription().compareTo(model.getDescription())) != 0) {

                continue;

            } else if (!model.getType().isEmpty()
                    && (current.getType().compareTo(model.getType())) != 0) {

                continue;

            } else if (!model.getRightsHolder().isEmpty()
                    && (current.getRightsHolder().compareTo(model.getRightsHolder())) != 0) {

                continue;

            } else if (!model.getCreator().isEmpty()
                    && (current.getCreator().compareTo(model.getCreator())) != 0) {

                continue;

            } else if (!model.getPublisher().isEmpty()
                    && (current.getPublisher().compareTo(model.getPublisher())) != 0) {

                continue;

            } else if (!model.getDate().isEmpty()
                    && (current.getDate().compareTo(model.getDate())) != 0) {

                continue;

            } else if (!model.getLanguage().isEmpty()
                    && (current.getLanguage().compareTo(model.getLanguage())) != 0) {

                continue;

            } else if (!model.getIdentifier().isEmpty()
                    && (current.getIdentifier().compareTo(model.getIdentifier())) != 0) {

                continue;

            }

            result.add(current);

        }

        return result;

    }

    public boolean insertFile(FileClass file) {

        if (searchFile(file.getKey()) == null) {

            catalog.getFile().add(file);
            saveCatalog(CATALOG_PATH);
            return true;

        }

        return false;

    }

    public void saveCatalog(String path) {

        try {

            byte[] data;
            data = marshalCatalog(catalog);
            FileOutputStream out = new FileOutputStream(path);
            out.write(data);

        } catch (IOException ex) {

            System.err.println("Erro ao salvar o catalogo " + path);

        }

    }

    @SuppressWarnings("unchecked")
    public CatalogClass loadCatalog(String path) {

        try {

            FileInputStream in = new FileInputStream(path);

            byte[] data = new byte[in.available()];

            in.read(data);

            return unmarshalCatalog(data);

        } catch (IOException ex) {

            System.err.println("Catalogo " + path + " não encontrado");

        }

        return null;

    }

    public void saveFile(FileClass file, String path) {

        try {

            byte[] data;
            data = marshalFile(file);
            FileOutputStream out = new FileOutputStream(path);
            out.write(data);

        } catch (IOException ex) {

            System.err.println("Erro ao salvar o arquivo " + path);

        }
    }

    @SuppressWarnings("unchecked")
    public FileClass loadFile(String path) {

        try {

            FileInputStream in = new FileInputStream(path);

            byte[] data = new byte[in.available()];
            in.read(data);

            return unmarshalFile(data);

        } catch (IOException ex) {

            System.err.println("Arquivo " + path + " não encontrado");

        }

        return null;

    }

    public byte[] marshalCatalog(CatalogClass catalog) {

        try {

            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            JAXBElement<CatalogClass> cc = factory.createCatalog(catalog);
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));

            StringWriter sw = new StringWriter();
            m.marshal(cc, sw);
            return sw.toString().getBytes();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
            System.err.println("Erro no formato do catalogo XML.");

        }

        return null;

    }

    public CatalogClass unmarshalCatalog(byte[] data) {

        CatalogClass catalog = factory.createCatalogClass();

        try {

            ByteArrayInputStream in = new ByteArrayInputStream(data);
            if (in == null) {
                return null;
            }
            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            Unmarshaller u = jc.createUnmarshaller();
            JAXBElement<CatalogClass> cc;
            cc = (JAXBElement<CatalogClass>) u.unmarshal(in);
            catalog = (CatalogClass) cc.getValue();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
//			e.printStackTrace();
            System.err.println("Formato do catalogo XML inválido");

        }

        return catalog;

    }

    public byte[] marshalFile(FileClass file) {

        try {

            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            JAXBElement<FileClass> fc = factory.createFile(file);
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));

//	     		m.marshal( fc, new FileOutputStream(path) );
            StringWriter sw = new StringWriter();
            m.marshal(fc, sw);

            return sw.toString().getBytes();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
            e.printStackTrace();

        }

        return null;

    }

    @SuppressWarnings("unchecked")
    public FileClass unmarshalFile(byte[] data) {

        try {

            ByteArrayInputStream in = new ByteArrayInputStream(data);
            if (in == null) {
                return null;
            }
            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            Unmarshaller u = jc.createUnmarshaller();
            JAXBElement<FileClass> fc = (JAXBElement<FileClass>) u.unmarshal(in);
            FileClass file = (FileClass) fc.getValue();
            return file;

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
//			e.printStackTrace();
            System.err.println("Formato do arquivo XML inválido");

        }

        return null;

    }

    public void sendData(int type, byte[] data) throws IOException {

        dos.writeInt(type);
        dos.writeInt(data.length);
        dos.write(data,0,data.length);

    }

    public int recvType() throws IOException {

        return dis.readInt();

    }

    public byte[] recvData() throws IOException {

        int length;
        length = dis.readInt();
        byte[] data = new byte[length];
        dis.readFully(data);

        return data;

    }

}
